package com.example.weatherpromax.logic

/*
内容：天气界面仓库层
功能：定义仓库层，实现网络请求的发起，并向上给出一个可供处理的LiveData对象
 */

import androidx.lifecycle.liveData
import com.example.weatherpromax.logic.model.Weather
import com.example.weatherpromax.logic.network.WeatherNetwork
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.Dispatchers
import java.lang.Exception
import java.lang.RuntimeException
import kotlin.coroutines.CoroutineContext

object Repository {

    //访问天气信息
    fun refreshWeather(lng: String, lat: String) = fire(Dispatchers.IO) {
        coroutineScope {
            val deferredRealtime = async {
                WeatherNetwork.getRealtimeWeather(lng, lat)
            }
            val deferredHourly = async {
                WeatherNetwork.getHourlyWeather(lng, lat)
            }
            val deferredDaily = async {
                WeatherNetwork.getDailyWeather(lng, lat)
            }
            val realtimeResponse = deferredRealtime.await()
            val hourlyResoponse = deferredHourly.await()
            val dailyResponse = deferredDaily.await()

            //如果三者请求状态均为ok，则打包为weather对象并发送出去
            if (realtimeResponse.status == "ok" && dailyResponse.status == "ok" && hourlyResoponse.status == "ok") {
                val weather = Weather(realtimeResponse.result.realtime, hourlyResoponse.result.hourly, dailyResponse.result.daily)
                Result.success(weather)
            }else {
                Result.failure (
                    RuntimeException(
                        "realtime response status is ${realtimeResponse.status}" + "hourly response status is ${hourlyResoponse.status}" + "daily response status is ${dailyResponse.status}"
                    )
                )
            }
        }
    }

    /*
    按照liveData（）方法定义的高阶函数，调用fire函数的同时会调用liveData方法，且统一进行try catch处理
    在try catch语句中传入Lambda表达式中的代码，最后获取执行结果并发射出去
     */
    private fun <T> fire(context: CoroutineContext, block: suspend () -> Result<T>) = liveData<Result<T>>(context) {
        val result = try {
            block()
        }catch (e: Exception) {
            Result.failure<T>(e)
        }
        emit(result)
    }
}